/**
 * 函数柯里化
 * 分析：
柯里化的本质是**收集到一定数量的参数（称为生产资料更为合适）**之后才去执行既定的函数，如果参数的数目小于既定函数执行所需要的个数则不执行，而是继续收集参数。

如果用代码来表示，可以设既定函数为fn，柯里化之后映射成为函数g，g在执行的时候会对积累到的参数的数目进行判断，
如果数目是足够的，则返回f的执行结果（相当于执行了fn），如果参数的数目不够，
则将此次调用传入的参数累积起来，然后返回函数g'，等待下一次调用。**返回的g'函数和g具有相同的功能。

注：fn.length 能拿到行参数个数
 * @param {*} fn
 * @param {*} currentParams
 */
function _KL(fn, currentParams = []) {
  // 校验
  if (typeof fn !== "function") throw new TypeError("fn 必须是一个函数");

  return function (...rest) {
    // 合并参数
    let params = [...rest, ...currentParams];
    if (params.length >= fn.length) {
      // 参数积累到了fn的形参个数，执行fn
      return fn.call(this, ...params);
    }

    // 否则继续返回
    return _KL(fn, params);
  };
}

// eg:
function add(a, b, c) {
  return a + b + c;
}

const c_add = _KL(add);

console.log(c_add(1)(2)(3)); // 6
console.log(c_add(1, 2)(3)); // 6
console.log(c_add(1)(2, 3)); // 6
console.log(c_add(1, 2, 3)); // 6
